import json
from typing import List, Dict, Any, Optional
from pathlib import Path
from loguru import logger
from datetime import datetime
import shutil

from .models import ScriptModel, ScriptFilter, ExecutionResult, ScriptStatus


class ScriptManager:
    """脚本管理器"""
    
    def __init__(self, scripts_dir: str = "scripts"):
        self.scripts_dir = Path(scripts_dir)
        self.scripts_dir.mkdir(exist_ok=True)
        
        # 创建子目录
        (self.scripts_dir / "active").mkdir(exist_ok=True)
        (self.scripts_dir / "archived").mkdir(exist_ok=True)
        (self.scripts_dir / "drafts").mkdir(exist_ok=True)
        
        self._scripts_cache: Dict[str, ScriptModel] = {}
        self._load_all_scripts()
    
    def _load_all_scripts(self) -> None:
        """加载所有脚本"""
        try:
            self._scripts_cache.clear()
            
            # 遍历所有脚本文件
            for script_file in self.scripts_dir.rglob("*.json"):
                try:
                    script = self.load_script_from_file(script_file)
                    if script:
                        self._scripts_cache[script.id] = script
                except Exception as e:
                    logger.warning(f"加载脚本文件失败 {script_file}: {e}")
            
            logger.info(f"已加载 {len(self._scripts_cache)} 个脚本")
            
        except Exception as e:
            logger.error(f"加载脚本失败: {e}")
    
    def load_script_from_file(self, file_path: Path) -> Optional[ScriptModel]:
        """从文件加载脚本"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            
            script = ScriptModel(**data)
            script.file_path = str(file_path)
            return script
            
        except Exception as e:
            logger.error(f"从文件加载脚本失败 {file_path}: {e}")
            return None
    
    def save_script(self, script: ScriptModel) -> bool:
        """保存脚本"""
        try:
            # 确定保存路径
            if script.file_path:
                file_path = Path(script.file_path)
            else:
                # 根据状态选择目录
                if script.status == ScriptStatus.DRAFT:
                    subdir = "drafts"
                elif script.status == ScriptStatus.ARCHIVED:
                    subdir = "archived"
                else:
                    subdir = "active"
                
                filename = f"{script.id}.json"
                file_path = self.scripts_dir / subdir / filename
                script.file_path = str(file_path)
            
            # 确保目录存在
            file_path.parent.mkdir(parents=True, exist_ok=True)
            
            # 更新时间戳
            script.updated_at = datetime.now()
            
            # 保存到文件
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(script.dict(), f, ensure_ascii=False, indent=2, default=str)
            
            # 更新缓存
            self._scripts_cache[script.id] = script
            
            logger.info(f"脚本已保存: {script.name} -> {file_path}")
            return True
            
        except Exception as e:
            logger.error(f"保存脚本失败: {e}")
            return False
    
    def get_script(self, script_id: str) -> Optional[ScriptModel]:
        """获取脚本"""
        return self._scripts_cache.get(script_id)
    
    def get_all_scripts(self) -> List[ScriptModel]:
        """获取所有脚本"""
        return list(self._scripts_cache.values())
    
    def delete_script(self, script_id: str) -> bool:
        """删除脚本"""
        try:
            script = self._scripts_cache.get(script_id)
            if not script:
                return False
            
            # 删除文件
            if script.file_path and Path(script.file_path).exists():
                Path(script.file_path).unlink()
            
            # 从缓存中删除
            del self._scripts_cache[script_id]
            
            logger.info(f"脚本已删除: {script.name}")
            return True
            
        except Exception as e:
            logger.error(f"删除脚本失败: {e}")
            return False
    
    def duplicate_script(self, script_id: str, new_name: str = None) -> Optional[ScriptModel]:
        """复制脚本"""
        try:
            original = self._scripts_cache.get(script_id)
            if not original:
                return None
            
            # 创建副本
            script_data = original.dict()
            script_data.pop('id')  # 移除ID，让系统生成新的
            script_data.pop('file_path', None)  # 移除文件路径
            script_data['name'] = new_name or f"{original.name} (副本)"
            script_data['created_at'] = datetime.now()
            script_data['updated_at'] = datetime.now()
            script_data['execution_count'] = 0
            script_data['last_execution'] = None
            script_data['success_rate'] = 0.0
            
            new_script = ScriptModel(**script_data)
            
            # 保存副本
            if self.save_script(new_script):
                return new_script
            return None
            
        except Exception as e:
            logger.error(f"复制脚本失败: {e}")
            return None
    
    def search_scripts(self, script_filter: ScriptFilter) -> List[ScriptModel]:
        """搜索脚本"""
        try:
            results = []
            
            for script in self._scripts_cache.values():
                if self._matches_filter(script, script_filter):
                    results.append(script)
            
            # 按更新时间倒序排列
            results.sort(key=lambda x: x.updated_at, reverse=True)
            return results
            
        except Exception as e:
            logger.error(f"搜索脚本失败: {e}")
            return []
    
    def _matches_filter(self, script: ScriptModel, script_filter: ScriptFilter) -> bool:
        """检查脚本是否匹配过滤条件"""
        # 名称匹配
        if script_filter.name and script_filter.name.lower() not in script.name.lower():
            return False
        
        # 状态匹配
        if script_filter.status and script.status != script_filter.status:
            return False
        
        # 浏览器类型匹配
        if script_filter.browser_type and script.browser_type != script_filter.browser_type:
            return False
        
        # 分类匹配
        if script_filter.category and script.category != script_filter.category:
            return False
        
        # 标签匹配
        if script_filter.tags:
            if not any(tag in script.tags for tag in script_filter.tags):
                return False
        
        # 创建时间匹配
        if script_filter.created_after and script.created_at < script_filter.created_after:
            return False
        
        if script_filter.created_before and script.created_at > script_filter.created_before:
            return False
        
        return True
    
    def get_script_statistics(self) -> Dict[str, Any]:
        """获取脚本统计信息"""
        try:
            stats = {
                "total_scripts": len(self._scripts_cache),
                "by_status": {},
                "by_browser": {},
                "by_category": {},
                "execution_stats": {
                    "total_executions": 0,
                    "average_success_rate": 0.0
                }
            }
            
            total_success_rate = 0.0
            scripts_with_executions = 0
            
            for script in self._scripts_cache.values():
                # 按状态统计
                status = script.status.value
                stats["by_status"][status] = stats["by_status"].get(status, 0) + 1
                
                # 按浏览器统计
                browser = script.browser_type.value
                stats["by_browser"][browser] = stats["by_browser"].get(browser, 0) + 1
                
                # 按分类统计
                category = script.category or "未分类"
                stats["by_category"][category] = stats["by_category"].get(category, 0) + 1
                
                # 执行统计
                stats["execution_stats"]["total_executions"] += script.execution_count
                if script.execution_count > 0:
                    total_success_rate += script.success_rate
                    scripts_with_executions += 1
            
            # 计算平均成功率
            if scripts_with_executions > 0:
                stats["execution_stats"]["average_success_rate"] = total_success_rate / scripts_with_executions
            
            return stats
            
        except Exception as e:
            logger.error(f"获取统计信息失败: {e}")
            return {}
    
    def export_script(self, script_id: str, export_path: str) -> bool:
        """导出脚本"""
        try:
            script = self._scripts_cache.get(script_id)
            if not script:
                return False
            
            export_data = {
                "script": script.dict(),
                "exported_at": datetime.now().isoformat(),
                "version": "1.0"
            }
            
            with open(export_path, 'w', encoding='utf-8') as f:
                json.dump(export_data, f, ensure_ascii=False, indent=2, default=str)
            
            logger.info(f"脚本已导出到: {export_path}")
            return True
            
        except Exception as e:
            logger.error(f"导出脚本失败: {e}")
            return False
    
    def import_script(self, import_path: str) -> Optional[ScriptModel]:
        """导入脚本"""
        try:
            with open(import_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            
            if "script" not in data:
                # 直接导入脚本数据
                script_data = data
            else:
                # 从导出格式中提取脚本数据
                script_data = data["script"]
            
            # 创建新的脚本ID和文件路径
            script_data.pop('id', None)
            script_data.pop('file_path', None)
            script_data['created_at'] = datetime.now()
            script_data['updated_at'] = datetime.now()
            
            script = ScriptModel(**script_data)
            
            if self.save_script(script):
                logger.info(f"脚本已导入: {script.name}")
                return script
            return None
            
        except Exception as e:
            logger.error(f"导入脚本失败: {e}")
            return None
    
    def backup_scripts(self, backup_path: str) -> bool:
        """备份所有脚本"""
        try:
            backup_dir = Path(backup_path)
            backup_dir.mkdir(parents=True, exist_ok=True)
            
            # 创建时间戳目录
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            backup_subdir = backup_dir / f"scripts_backup_{timestamp}"
            
            # 复制整个脚本目录
            shutil.copytree(self.scripts_dir, backup_subdir)
            
            logger.info(f"脚本已备份到: {backup_subdir}")
            return True
            
        except Exception as e:
            logger.error(f"备份脚本失败: {e}")
            return False